
package visualisation;


import javax.swing.*
import javax.swing.tree.DefaultMutableTreeNode as TreeNode
import groovy.swing.SwingBuilder
import primitives.cluster.*;
import search.util.*;
import search.fitnessfunctions.*;
import bunchbridge.*;
import primitives.graph.*;
class BunchToTree{
	
	
	static def parseSIL(filename){
		def ret = [:]
		def p = ~/level\d+.sil/
		def match = ~/SS\(clusterLvl(\d+)Num(\d+)\)=(((, )?([\w\/\.]+))+)/
		db("Starting file processing")
		new File(filename).eachFileMatch(p){
			f ->
			db("Processing $f")
			f.eachLine(){
				line -> 								
				db("ln [$line]")
				def matcher = match.matcher(line);

				def io=0
				if(matcher.matches()){
					if(ret[matcher[0][1]] == null) ret[matcher[0][1]] = [:]
					db("setting ret")
					ret[matcher[0][1]][matcher[0][2]] = matcher[0][3].split(", ")
				}

			}
		}
		
		db("Finished parsing all SIL files")
		

		return ret;
	}
	
	static def contains(parent, child){
		def ret = true;
		child.each{
			if(parent.findAll{pch -> pch == it}.size() == 0) ret = false;


		}
		return ret;
		
	}
	
	static def db(msg){
	
	//	println(msg)
	}
	

	static def void main(String[] args){

		db("Entered main")
		String filename = args[0];
		String dotName = null
		if(args.length >= 2){
			db("Using ${args[1]} for dot input.")
			dotName = args[1];
		}
		db("parsing assignments...")
		def assignments = parseSIL(filename)
		db("SIL directory successfully parsed.")
//		println assignments;
		
		int max = -1;
		assignments.each{k, _ -> 
//			println "$k"
			if(k > max) max = k as int
		}
//		println "$max"

		
		
		def root = "ROOT"
		def tree = ["ROOT":null]
		def par = tree[root];
		
		def childrenOf = [:]
		
		def parents = [:]
		

//		println "max is $max";
/*		if(max as int == 1){
					db("processing max")

					assignments[max].each{
						num, _ ->
						db("processing assignments[$level] -> $num")					
						parents[level] = [(num):root];
						childrenOf[root]= [(num):[level,num]]
	//					childrenOf[root][num] = [level,num] 
	

					}
			
		}else{*/
			for(int lvl = max; lvl > 0; lvl--){
				def level = lvl as String
				if(level == max as String){

					db("processing max")

					assignments[level].each{
						num, _ ->
						db("processing assignments[$level] -> $num")					
						parents[level] = [(num):root];
						if(childrenOf[root] == null) childrenOf[root]= [(num):[level,num]]
	//					childrenOf[root][num] = [level,num] 
	

					}
				}else{
	//				println level
					parents[level] = [:]
					assignments[level].each{
						num, contents ->
						assignments[(lvl+1 as String)].each{
							parentnum, parentcontents ->
							if(contains(parentcontents, contents)){
								parents[level][num] = [(lvl+1 as String): parentnum]
								if(childrenOf[(lvl+1) as String,parentnum] == null) {
									childrenOf[(lvl+1) as String,parentnum] = []
								}
								childrenOf[(lvl+1) as String,parentnum].add([level,num])
							}
						}
					}
				}
				
			}
		//}
		//println parents;
		def c = childrenOf[root]["0"]

//		println c;
		def visitors = [c];
		
		while(!visitors.isEmpty()){
			def current = visitors.pop();
			def tabs = "";
			int ct = current[0] as int;
			for(int i = 0; i< max-(ct+1); i++){
				tabs += "\t"
			}
			//if(childrenOf[current] != null && childrenOf[current].size() > 1)
			//	println "${tabs}${current[0]},${current[1]}";
			if(childrenOf[current] != null)
				visitors.addAll(childrenOf[current])
			//else
			//	println "\t" + tabs + assignments[current[0]][current[1]]
		}
		
		def cnodes = [:]
		
		int x = 0;
		childrenOf.keySet().each{
			cnodes[it] = new ClusterNode();
			if(it.equals("ROOT")) cnodes[it].setID(-0xBEEF);
			else cnodes[it].setID((it[0] as int) * 10 + (it[1] as int) )
		}

		
		
		if(dotName != null){
			
		            ClusterHead toCluster = TreeLoader2.loadTreeFromDot(dotName);
					
					def nodes = [:]
					toCluster.nodes.each{
						nodes[it.label] = it;
					}
					
					
					ClusterHead blank = new ClusterHead();
					def chit = false;
					visitors = [c];
		
					while(!visitors.isEmpty()){
						def current = visitors.pop();
						def tabs = "";
						int ct = current[0] as int;
						for(int i = 0; i< max-(ct+1); i++){
							tabs += "\t"
						}
						if(childrenOf[current] != null && childrenOf[current].size() > 1){
//							println "${tabs}${current[0]},${current[1]}";
							db("$current has been chosen to be the global parent")
							if(!chit){
								chit = true;
								cnodes[current] = blank
								blank.setID(3)
							}
						}
						if(childrenOf[current] != null){
							db("going to add children of $current now : ${childrenOf[current]}")
							visitors.addAll(childrenOf[current])
							//ADD cnodes[CHILD] TO cnodes[current]
							childrenOf[current].each{
								if(cnodes[it] == null) cnodes[it] = new ClusterNode();
								cnodes[current].addChild(cnodes[it])
							}
						}
						else{
							db("children of $current is null, so adding each assignment to $current")
							//add nodes to cnodes[current]
//							println "\t" + tabs + assignments[current[0]][current[1]]
							assignments[current[0]][current[1]].each{
								db("$current will be parent of $it")
//								println it;
								if(nodes[it] != null){
									
									db("$it has been found in nodes[]")
									def cl =  new ClusterLeaf();

									cl.addNode(nodes[it]);
									if(cnodes[current] != null){
										cnodes[current].addChild(cl)
										cnodes[current].setID((current[0] as int) * 10 + (current[1] as int))
									}			
									if(!chit){
										db("adding these children to blank as there isn't a parent.")
										blank.addChild(cl);
									}					
								}
								else{
									//println "NODE $it not found!"
								
									nodes.each{
										k,v ->
										//println "$k : $v"
									}
									/*
									assignments.each{k,v ->
										println "$k [$v]"
									}*/
									System.exit(-1)
								}
							}
						}
					}
//					ClusterUtils.prettyPrintTree(blank);
					//blank.nodes.each{println it;}
					
					if(args.length >= 3){
						def outname = args[2]
						
						File outpath = new File(outname)
						
			            if (!outpath.exists()) {
			                outpath.getParentFile().mkdirs();
			                outpath.createNewFile();
			            }

						
			            FileOutputStream fos = null;

			            ObjectOutputStream out = null;
			            fos = new FileOutputStream(outpath);
			            out = new ObjectOutputStream(fos);
						//(end)
			            out.writeObject(blank);
			            out.close();

					
					}
			
		}
		



	}
}